import mqtt, { MqttClient, type IClientOptions } from "mqtt";
import appEnvironment from "@/app-environments";

interface MQTTInstance {
  isConnected: Ref<boolean>;
  client: MqttClient | null;
  connect: () => void;
  disconnect: () => void;
  publish: (topic: string, message: string) => void;
  subscribe: (
    topic: string,
    callback: (topic: string, message: string) => void
  ) => void;
  unsubscribe: (
    topic: string,
    callback?: (topic: string, message: string) => void
  ) => void;
}
const {
  networkHosts: {
    mqttServer1: { fullHost },
  },
} = appEnvironment;

const DEFAULT_BROKER_URL = `${fullHost}/mqtt`;
const instances = new Map<string, MQTTInstance>();

function createMQTTInstance(
  brokerUrl: string,
  options?: IClientOptions
): MQTTInstance {
  const state = reactive({
    isConnected: false,
    client: null as MqttClient | null,
    subscriptions: new Map<
      string,
      Set<(topic: string, message: string) => void>
    >(),
  });

  const connect = () => {
    // console.log("Connecting to MQTT broker:", brokerUrl);
    if (state.client?.connected) return;

    state.client = mqtt.connect(brokerUrl, options);

    state.client.on("connect", () => {
      state.isConnected = true;
    });

    state.client.on("message", (topic, message) => {
      const handlers = state.subscriptions.get(topic);
      handlers?.forEach((handler) => handler(topic, message.toString()));
    });

    state.client.on("error", (error) => {
      console.error("MQTT Error:", error);
    });
  };

  const disconnect = () => {
    state.client?.end();
    state.isConnected = false;
  };

  const publish = (topic: string, message: string) => {
    state.client?.publish(topic, message);
  };

  const subscribe = (
    topic: string,
    callback: (topic: string, message: string) => void
  ) => {
    if (!state.subscriptions.has(topic)) {
      state.subscriptions.set(topic, new Set());
      state.client?.subscribe(topic);
    }
    state.subscriptions.get(topic)?.add(callback);
  };

  const unsubscribe = (
    topic: string,
    callback?: (topic: string, message: string) => void
  ) => {
    const handlers = state.subscriptions.get(topic);
    if (!handlers) return;

    if (callback) {
      // 移除指定回调
      handlers.delete(callback);
      // 若回调集合为空，则取消订阅并删除主题
      if (handlers.size === 0) {
        state.subscriptions.delete(topic);
        state.client?.unsubscribe(topic);
      }
    } else {
      // 移除整个主题的订阅
      state.subscriptions.delete(topic);
      state.client?.unsubscribe(topic);
    }
  };

  return {
    isConnected: toRef(state, "isConnected"),
    client: state.client as MqttClient | null,
    connect,
    disconnect,
    publish,
    subscribe,
    unsubscribe,
  };
}

export function useMqtt(
  brokerUrl?: string,
  options?: IClientOptions
): MQTTInstance;
// eslint-disable-next-line no-redeclare
export function useMqtt(options?: IClientOptions): MQTTInstance;
// eslint-disable-next-line no-redeclare
export function useMqtt(...args: any[]): MQTTInstance {
  let finalUrl = DEFAULT_BROKER_URL;
  let finalOptions: IClientOptions = {};

  if (typeof args[0] === "string") {
    finalUrl = args[0];
    finalOptions = args[1] || {};
  } else if (typeof args[0] === "object") {
    finalOptions = args[0];
    if (finalOptions.host) {
      const protocol = finalOptions.protocol === "wss" ? "wss" : "ws";
      const defaultPort = protocol === "wss" ? 443 : 80;
      finalUrl = `${protocol}://${finalOptions.host}:${finalOptions.port || defaultPort}`;
    }
  }
  // console.log("Using MQTT broker URL:", finalUrl);

  if (!instances.has(finalUrl)) {
    instances.set(
      finalUrl,
      createMQTTInstance(finalUrl, {
        clientId: "browserClient_" + Math.random().toString(16).substr(2, 8),
        ...finalOptions,
      })
    );
  }

  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
  return instances.get(finalUrl)!;
}
